home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD 2.1 / Amiga Developer CD v2.1.iso / Reference / ROM_Kernel_Manuals / Devices / dev_examples / Cia_Interval.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-20  |  10.1 KB  |  424 lines

  1. /*
  2.  * Cia_Interval.c
  3.  *
  4.  * Demonstrate allocation and use of a cia interval timer
  5.  *
  6.  * Compile with SAS C 5.10  lc -b1 -cfistq -v -y -L
  7.  *
  8.  * Run from CLI only
  9.  */
  10.  
  11. #include <exec/types.h>
  12. #include <exec/memory.h>
  13. #include <exec/tasks.h>
  14. #include <exec/interrupts.h>
  15. #include <hardware/cia.h>
  16. #include <resources/cia.h>
  17.  
  18. #include <clib/exec_protos.h>
  19. #include <clib/cia_protos.h>
  20.  
  21. #include <stdlib.h>
  22. #include <stdio.h>
  23. #include <string.h>
  24.  
  25.  
  26. /* prototypes */
  27.  
  28. void    StartTimer      (struct freetimer *ft, struct exampledata *ed);
  29. int     FindFreeTimer   (struct freetimer *ft, int preferA);
  30. int     TryTimer        (struct freetimer *ft);
  31. void    main            ( USHORT, char **);
  32.  
  33.  
  34. /* see usage of these defines in StartTimer() below */
  35.  
  36. #define COUNTDOWN 20
  37. #define HICOUNT 0xFF
  38. #define LOCOUNT 0xFF
  39.  
  40. #define STOPA_AND  CIACRAF_TODIN |CIACRAF_PBON | CIACRAF_OUTMODE | CIACRAF_SPMODE
  41.  
  42.         /*
  43.         ;
  44.         ; AND mask for use with control register A
  45.         ; (interval timer A on either CIA)
  46.         ;
  47.         ; STOP -
  48.         ;       START bit 0 == 0 (STOP IMMEDIATELY)
  49.         ;       PBON  bit 1 == same
  50.         ;       OUT   bit 2 == same
  51.         ;       RUN   bit 3 == 0 (SET CONTINUOUS MODE)
  52.         ;       LOAD  bit 4 == 0 (NO FORCE LOAD)
  53.         ;       IN    bit 5 == 0 (COUNTS 02 PULSES)
  54.         ;       SP    bit 6 == same
  55.         ;       TODIN bit 7 == same (unused on ciacra)
  56.  
  57.         */
  58.  
  59. #define STOPB_AND  CIACRBF_ALARM | CIACRBF_PBON | CIACRBF_OUTMODE
  60.  
  61.         /*
  62.         ;
  63.         ; AND mask for use with control register B
  64.         ; (interval timer B on either CIA)
  65.         ;
  66.         ; STOP -
  67.         ;       START bit 0 == 0 (STOP IMMEDIATELY)
  68.         ;       PBON  bit 1 == same
  69.         ;       OUT   bit 2 == same
  70.         ;       RUN   bit 3 == 0 (SET CONTINUOUS MODE)
  71.         ;       LOAD  bit 4 == 0 (NO FORCE LOAD)
  72.         ;       IN0   bit 5 == 0 (COUNTS 02 PULSES)
  73.         ;       IN1   bit 6 == 0 (COUNTS 02 PULSES)
  74.         ;       ALARM bit 7 == same (TOD alarm control bit)
  75.  
  76.         */
  77.  
  78. #define STARTA_OR  CIACRAF_START
  79.  
  80.         /*
  81.         ;
  82.         ; OR mask for use with control register A
  83.         ; (interval timer A on either CIA)
  84.         ;
  85.         ; START -
  86.         ;
  87.         ;       START bit 0 == 1 (START TIMER)
  88.         ;
  89.         ;       All other bits unaffected.
  90.         ;
  91.  
  92.         */
  93.  
  94. #define STARTB_OR  CIACRBF_START
  95.  
  96.         /*
  97.         ;
  98.         ; OR mask for use with control register B
  99.         ; (interval timer A on either CIA)
  100.         ;
  101.         ; START -
  102.         ;
  103.         ;       START bit 0 == 1 (START TIMER)
  104.         ;
  105.         ;       All other bits unaffected.
  106.         ;
  107.  
  108.         */
  109.  
  110.  
  111. /*
  112.  * Structure which will be used to hold all relevant information about
  113.  * the cia timer we manage to allocate.
  114.  *
  115.  */
  116.  
  117. struct freetimer
  118. {
  119.     struct Library *ciabase;        /* CIA Library Base             */
  120.     ULONG  timerbit;                /* timer bit allocated          */
  121.     struct CIA *cia;                /* ptr to hardware              */
  122.     UBYTE *ciacr;                   /* ptr to control register      */
  123.     UBYTE *cialo;                   /* ptr to low byte of timer     */
  124.     UBYTE *ciahi;                   /* ptr to high byte of timer    */
  125.     struct Interrupt timerint;      /* Interrupt structure          */
  126.     UBYTE  stopmask;                /* Stop/set-up timer            */
  127.     UBYTE  startmask;               /* Start timer                  */
  128. };
  129.  
  130. /*
  131.  * Structure which will be used by the interrupt routine called
  132.  * when our cia interval timer generates an interrupt.
  133.  *
  134.  */
  135.  
  136. struct exampledata
  137. {
  138.     struct Task *task;      /* task to signal */
  139.     ULONG   signal;         /* Signal bit to use */
  140.     ULONG   counter;
  141. };
  142.  
  143.  
  144. struct CIA *ciaa = (struct CIA *)0xbfe001;
  145. struct CIA *ciab = (struct CIA *)0xbfd000;
  146.  
  147.  
  148. #ifdef LATTICE
  149. int CXBRK(void) { return(0); }  /* Disable SAS CTRL/C handling */
  150. int chkabort(void) { return(0); }  /* really */
  151. #endif
  152.  
  153. /*
  154.  * This is the interrupt routine which will be called when our CIA
  155.  * interval timer counts down.
  156.  *
  157.  * This example decrements a counter each time the interrupt routine
  158.  * is called until the counter reaches 0, at which time it signals
  159.  * our main task.
  160.  *
  161.  * Note that interrupt handling code should be efficient, and will
  162.  * generally be written in assembly code.  Signaling another task
  163.  * such as this example does is also a useful way of handling
  164.  * interrupts in an expedient manner.
  165.  */
  166.  
  167. void __asm ExampleInterrupt(register __a1 struct exampledata *ed)
  168. {
  169. if (ed->counter)
  170.     {
  171.     ed->counter--;                  /* decrement counter */
  172.     }
  173. else
  174.     {
  175.     ed->counter = COUNTDOWN;        /* reset counter     */
  176.  
  177.     Signal(ed->task,(1L << ed->signal));
  178.     }
  179. }
  180.  
  181.  
  182. /***********************************
  183.  *  main()
  184.  ***********************************/
  185.  
  186. void main(USHORT argc,char **argv)
  187. {
  188. struct freetimer ft;
  189. struct exampledata ed;
  190.  
  191. /* Set up data which will be passed to interrupt */
  192.  
  193. ed.task = FindTask(0L);
  194.  
  195. if (ed.signal = AllocSignal(-1L))
  196.     {
  197.     /* Prepare freetimer structure : set-up interrupt */
  198.  
  199.     ft.timerint.is_Node.ln_Type = NT_INTERRUPT;
  200.     ft.timerint.is_Node.ln_Pri  = 0;
  201.     ft.timerint.is_Node.ln_Name = "cia_example";
  202.  
  203.     ft.timerint.is_Data         = (APTR)&ed;
  204.     ft.timerint.is_Code         = (APTR)ExampleInterrupt;
  205.  
  206.     /* Call function to find a free CIA interval timer
  207.      * with flag indicating that we prefer a CIA-A timer.
  208.      */
  209.  
  210.     printf("Attempting to allocate a free timer\n");
  211.  
  212.     if (FindFreeTimer(&ft,TRUE))
  213.         {
  214.         if (ft.cia == ciaa)
  215.             {
  216.             printf("CIA-A timer ");
  217.             }
  218.         else
  219.             {
  220.             printf("CIA-B timer ");
  221.             }
  222.  
  223.         if (ft.timerbit == CIAICRB_TA)
  224.             {
  225.             printf("A allocated\n");
  226.             }
  227.         else
  228.             {
  229.             printf("B allocated\n");
  230.             }
  231.  
  232.  
  233.         /* We found a free interval timer.  Let's start it running. */
  234.  
  235.         StartTimer(&ft,&ed);
  236.  
  237.         /* Wait for a signal */
  238.  
  239.         printf("Waiting for signal bit %ld\n",ed.signal);
  240.  
  241.         Wait(1L<<ed.signal);
  242.  
  243.         printf("We woke up!\n");
  244.  
  245.         /* Release the interval timer */
  246.  
  247.         RemICRVector(ft.ciabase,ft.timerbit,&ft.timerint);
  248.  
  249.         }
  250.     else
  251.         {
  252.         printf("No CIA interval timer available\n");
  253.         }
  254.  
  255.     FreeSignal(ed.signal);
  256.     }
  257. }
  258.  
  259.  
  260. /*
  261.  * This routine sets up the interval timer we allocated with
  262.  * AddICRVector().  Note that we may have already received one, or
  263.  * more interrupts from our timer.  Make no assumptions about the
  264.  * initial state of any of the hardware registers we will be using.
  265.  *
  266.  */
  267.  
  268. void StartTimer(struct freetimer *ft, struct exampledata *ed)
  269. {
  270. register struct CIA *cia;
  271.  
  272. cia = ft->cia;
  273.  
  274. /* Note that there are differences between control register A,
  275.  * and B on each CIA (e.g., the TOD alarm bit, and INMODE bits.
  276.  */
  277.  
  278. if (ft->timerbit == CIAICRB_TA)
  279.     {
  280.     ft->ciacr = &cia->ciacra;       /* control register A   */
  281.     ft->cialo = &cia->ciatalo;      /* low byte counter     */
  282.     ft->ciahi = &cia->ciatahi;      /* high byte counter    */
  283.  
  284.     ft->stopmask = STOPA_AND;       /* set-up mask values   */
  285.     ft->startmask = STARTA_OR;
  286.     }
  287. else
  288.     {
  289.     ft->ciacr = &cia->ciacrb;       /* control register B   */
  290.     ft->cialo = &cia->ciatblo;      /* low byte counter     */
  291.     ft->ciahi = &cia->ciatbhi;      /* high byte counter    */
  292.  
  293.     ft->stopmask = STOPB_AND;       /* set-up mask values   */
  294.     ft->startmask = STARTB_OR;
  295.     }
  296.  
  297.  
  298. /* Modify control register within Disable().  This is done to avoid
  299.  * race conditions since our compiler may generate code such as:
  300.  *
  301.  *      value = Read hardware byte
  302.  *      AND  value with MASK
  303.  *      Write value to hardware byte
  304.  *
  305.  * If we take a task switch in the middle of this sequence, two tasks
  306.  * trying to modify the same register could trash each others' bits.
  307.  *
  308.  * Normally this code would be written in assembly language using atomic
  309.  * instructions so that the Disable() would not be needed.
  310.  */
  311.  
  312.  
  313. Disable();
  314.  
  315. /* STOP timer, set 02 pulse count-down mode, set continuous mode */
  316.  
  317. *ft->ciacr &= ft->stopmask;
  318. Enable();
  319.  
  320. /* Clear signal bit - interrupt will signal us later */
  321. SetSignal(0L,1L<<ed->signal);
  322.  
  323. /* Count-down X # of times */
  324. ed->counter = COUNTDOWN;
  325.  
  326. /* Start the interval timer - we will start the counter after
  327.  * writing the low, and high byte counter values
  328.  */
  329.  
  330. *ft->cialo = LOCOUNT;
  331. *ft->ciahi = HICOUNT;
  332.  
  333. /* Turn on start bit - same bit for both A, and B control regs  */
  334.  
  335. Disable();
  336. *ft->ciacr |= ft->startmask;
  337.  
  338. Enable();
  339. }
  340.  
  341. /*
  342.  * A routine to find a free interval timer.
  343.  *
  344.  * This routine makes no assumptions about which interval timers
  345.  * (if any) are available for use.  Currently there are two interval
  346.  * timers per CIA chip.
  347.  *
  348.  * Because CIA usage may change in the future, your code should use
  349.  * a routine like this to find a free interval timer.
  350.  *
  351.  * Note that the routine takes a preference flag (which is used to
  352.  * to indicate that you would prefer an interval timer on CIA-A).
  353.  * If the flag is FALSE, it means that you would prefer an interval
  354.  * timer on CIA-B.
  355.  *
  356.  */
  357.  
  358. FindFreeTimer(struct freetimer *ft, int preferA)
  359. {
  360. struct CIABase *ciaabase, *ciabbase;
  361.  
  362. /* get pointers to both resource bases */
  363.  
  364. ciaabase = OpenResource(CIAANAME);
  365. ciabbase = OpenResource(CIABNAME);
  366.  
  367. /* try for a CIA-A timer first ? */
  368.  
  369. if (preferA)
  370.     {
  371.     ft->ciabase = ciaabase; /* library address  */
  372.     ft->cia     = ciaa;     /* hardware address */
  373.     }
  374. else
  375.     {
  376.     ft->ciabase = ciabbase; /* library address  */
  377.     ft->cia     = ciab;     /* hardware address */
  378.     }
  379.  
  380. if (TryTimer(ft))
  381.     return(TRUE);
  382.  
  383. /* try for an interval timer on the other cia */
  384.  
  385. if (!(preferA))
  386.     {
  387.     ft->ciabase = ciaabase; /* library address  */
  388.     ft->cia     = ciaa;     /* hardware address */
  389.     }
  390. else
  391.     {
  392.     ft->ciabase = ciabbase; /* library address  */
  393.     ft->cia     = ciab;     /* hardware address */
  394.     }
  395.  
  396. if (TryTimer(ft))
  397.     return(TRUE);
  398.  
  399. return(FALSE);
  400.  
  401. }
  402.  
  403. /*
  404.  * Try to obtain a free interval timer on a CIA.
  405.  */
  406.  
  407. TryTimer(struct freetimer *ft)
  408. {
  409.  
  410. if (!(AddICRVector(ft->ciabase,CIAICRB_TA,&ft->timerint)))
  411.     {
  412.     ft->timerbit = CIAICRB_TA;
  413.     return(TRUE);
  414.     }
  415.  
  416. if (!(AddICRVector(ft->ciabase,CIAICRB_TB,&ft->timerint)))
  417.     {
  418.     ft->timerbit = CIAICRB_TB;
  419.     return(TRUE);
  420.     }
  421.  
  422. return(FALSE);
  423. }
  424.